﻿// Decompiled with JetBrains decompiler
// Type: TaleWorlds.CampaignSystem.KingdomManager
// Assembly: TaleWorlds.CampaignSystem, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
// MVID: E85F8C15-4DF6-4E9C-A58A-29177E40D07A
// Assembly location: D:\steam\steamapps\common\Mount & Blade II Bannerlord\bin\Win64_Shipping_Client\TaleWorlds.CampaignSystem.dll

using Helpers;
using System;
using System.Collections.Generic;
using System.Linq;
using TaleWorlds.CampaignSystem.Actions;
using TaleWorlds.CampaignSystem.Election;
using TaleWorlds.CampaignSystem.MapEvents;
using TaleWorlds.CampaignSystem.Party;
using TaleWorlds.CampaignSystem.Party.PartyComponents;
using TaleWorlds.CampaignSystem.Settlements;
using TaleWorlds.Core;
using TaleWorlds.Library;
using TaleWorlds.Localization;
using TaleWorlds.SaveSystem;

#nullable disable
namespace TaleWorlds.CampaignSystem
{
  public class KingdomManager
  {
    [SaveableField(2)]
    public float PlayerMercenaryServiceNextRenewDay = -1f;
    [SaveableField(3)]
    public Hero PrisonerLordRansomOffered;
    public MBCampaignEvent QuarterHourlyTickEvent;

    internal static void AutoGeneratedStaticCollectObjectsKingdomManager(
      object o,
      List<object> collectedObjects)
    {
      ((KingdomManager) o).AutoGeneratedInstanceCollectObjects(collectedObjects);
    }

    protected virtual void AutoGeneratedInstanceCollectObjects(List<object> collectedObjects)
    {
      collectedObjects.Add((object) this.PrisonerLordRansomOffered);
    }

    internal static object AutoGeneratedGetMemberValuePlayerMercenaryServiceNextRenewDay(object o)
    {
      return (object) ((KingdomManager) o).PlayerMercenaryServiceNextRenewDay;
    }

    internal static object AutoGeneratedGetMemberValuePrisonerLordRansomOffered(object o)
    {
      return (object) ((KingdomManager) o).PrisonerLordRansomOffered;
    }

    public void OnSessionStart()
    {
      foreach (Clan clan in (List<Clan>) Clan.All)
        clan.UpdateStrength();
      if (!MBSaveLoad.IsUpdatingGameVersion || !(MBSaveLoad.LastLoadedGameVersion < ApplicationVersion.FromString("v1.2.0")))
        return;
      for (int index = 0; index < Kingdom.All.Count; ++index)
        this.ExpelConstantWarClansFromKingdom(Kingdom.All[index]);
    }

    internal void RegisterEvents()
    {
      CampaignEvents.SiegeCompletedEvent.AddNonSerializedListener((object) this, new Action<Settlement, MobileParty, bool, MapEvent.BattleTypes>(this.SiegeCompleted));
      CampaignEvents.RaidCompletedEvent.AddNonSerializedListener((object) this, new Action<BattleSideEnum, RaidEventComponent>(this.RaidCompleted));
      CampaignEvents.WarDeclared.AddNonSerializedListener((object) this, new Action<IFaction, IFaction, DeclareWarAction.DeclareWarDetail>(this.OnWarDeclared));
      CampaignEvents.DailyTickClanEvent.AddNonSerializedListener((object) this, new Action<Clan>(this.DailyTickClan));
      CampaignEvents.HourlyTickClanEvent.AddNonSerializedListener((object) this, new Action<Clan>(this.HourlyTickClan));
      this.QuarterHourlyTickEvent = CampaignPeriodicEventManager.CreatePeriodicEvent(CampaignTime.Hours(0.25f), CampaignTime.Zero);
      this.QuarterHourlyTickEvent.AddHandler(new MBCampaignEvent.CampaignEventDelegate(KingdomManager.QuarterHourlyTick));
    }

    private void ExpelConstantWarClansFromKingdom(Kingdom kingdom)
    {
      for (int index1 = kingdom.Clans.Count - 1; index1 >= 0; --index1)
      {
        Clan clan = kingdom.Clans[index1];
        if (clan.GetStanceWith((IFaction) kingdom).IsAtConstantWar)
        {
          for (int index2 = clan.WarPartyComponents.Count - 1; index2 >= 0; --index2)
          {
            WarPartyComponent warPartyComponent = clan.WarPartyComponents[index2];
            if (warPartyComponent.MobileParty.MapEvent != null)
              warPartyComponent.MobileParty.MapEvent.FinalizeEvent();
          }
          ChangeKingdomAction.ApplyByLeaveWithRebellionAgainstKingdom(clan, false);
        }
      }
    }

    private void OnWarDeclared(
      IFaction factionDeclaringWar,
      IFaction factionDeclaredWarAgainst,
      DeclareWarAction.DeclareWarDetail detail)
    {
      if (factionDeclaringWar is Clan)
        (factionDeclaringWar as Clan).Aggressiveness += (float) ((100.0 - (double) factionDeclaredWarAgainst.Aggressiveness) * 0.5);
      else
        (factionDeclaringWar as Kingdom).Aggressiveness += (float) ((100.0 - (double) factionDeclaredWarAgainst.Aggressiveness) * 0.5);
    }

    private void HourlyTickClan(Clan clan) => clan.UpdateStrength();

    private void DailyTickClan(Clan clan)
    {
      clan.Aggressiveness += -1f;
      if (clan.Kingdom == null || clan.Kingdom.RulingClan != clan)
        return;
      this.DailyTickKingdom(clan.Kingdom);
    }

    private void DailyTickKingdom(Kingdom kingdom) => kingdom.Aggressiveness += -1f;

    public void CreateKingdom(
      TextObject kingdomName,
      TextObject informalName,
      CultureObject culture,
      Clan founderClan,
      MBReadOnlyList<PolicyObject> initialPolicies = null,
      TextObject encyclopediaText = null,
      TextObject encyclopediaTitle = null,
      TextObject encyclopediaRulerTitle = null)
    {
      Kingdom kingdom1 = Kingdom.CreateKingdom("new_kingdom");
      if (encyclopediaTitle == null)
      {
        encyclopediaTitle = new TextObject("{=ZOEamqUd}Kingdom of {NAME}");
        encyclopediaTitle.SetTextVariable("NAME", founderClan.Name);
      }
      if (encyclopediaText == null)
      {
        encyclopediaText = !founderClan.IsRebelClan ? new TextObject("{=21yUheIy}The {KINGDOM_NAME} was created in {CREATION_YEAR} by {RULER.NAME}, a rising {CULTURE_ADJECTIVE} warlord.") : new TextObject("{=drZC1Frp}The {KINGDOM_NAME} was created in {CREATION_YEAR} by {RULER.NAME}, leader of a group of {CULTURE_ADJECTIVE} rebels.");
        encyclopediaText.SetTextVariable("KINGDOM_NAME", encyclopediaTitle);
        encyclopediaText.SetTextVariable("CREATION_YEAR", CampaignTime.Now.GetYear);
        encyclopediaText.SetTextVariable("CULTURE_ADJECTIVE", FactionHelper.GetAdjectiveForFactionCulture(culture));
        StringHelpers.SetCharacterProperties("RULER", founderClan.Leader.CharacterObject, encyclopediaText);
      }
      if (encyclopediaRulerTitle == null)
      {
        Kingdom kingdom2 = Kingdom.All.FirstOrDefault<Kingdom>((Func<Kingdom, bool>) (x => x.Culture == culture));
        encyclopediaRulerTitle = kingdom2 != null ? kingdom2.EncyclopediaRulerTitle : TextObject.Empty;
      }
      kingdom1.InitializeKingdom(kingdomName, informalName, culture, founderClan.Banner, founderClan.Color, founderClan.Color2, founderClan.HomeSettlement, encyclopediaText, encyclopediaTitle, encyclopediaRulerTitle);
      List<IFaction> factionList = new List<IFaction>(FactionManager.GetEnemyFactions((IFaction) founderClan));
      ChangeKingdomAction.ApplyByCreateKingdom(founderClan, kingdom1, false);
      foreach (IFaction faction2 in factionList)
        DeclareWarAction.ApplyByKingdomCreation((IFaction) kingdom1, faction2);
      if (initialPolicies != null)
      {
        foreach (PolicyObject initialPolicy in (List<PolicyObject>) initialPolicies)
          kingdom1.AddPolicy(initialPolicy);
      }
      CampaignEventDispatcher.Instance.OnKingdomCreated(kingdom1);
    }

    public void AbdicateTheThrone(Kingdom kingdom)
    {
      Clan rulingClan = kingdom.RulingClan;
      if (kingdom.Clans.Count<Clan>((Func<Clan, bool>) (x => !x.IsUnderMercenaryService)) > 1)
      {
        float num = float.MinValue;
        Clan clan1 = (Clan) null;
        foreach (Clan clan2 in (List<Clan>) kingdom.Clans)
        {
          if (clan2 != rulingClan && (double) clan2.Influence > (double) num)
          {
            num = clan2.Influence;
            clan1 = clan2;
          }
        }
        ChangeRulingClanAction.Apply(kingdom, clan1);
        KingSelectionKingdomDecision selectionKingdomDecision = new KingSelectionKingdomDecision(rulingClan, rulingClan);
        selectionKingdomDecision.IsEnforced = true;
        kingdom.AddDecision((KingdomDecision) selectionKingdomDecision, true);
      }
      else
      {
        ChangeKingdomAction.ApplyByLeaveKingdom(kingdom.RulingClan);
        foreach (Kingdom faction1 in (List<Kingdom>) Kingdom.All)
        {
          if (faction1.IsAtWarWith((IFaction) kingdom))
          {
            if (!faction1.IsAtWarWith((IFaction) rulingClan))
              DeclareWarAction.ApplyByDefault((IFaction) faction1, (IFaction) rulingClan);
          }
          else if (faction1.IsAtWarWith((IFaction) rulingClan))
            Debug.FailedAssert("Deviation in peace states between ruling clan & kingdom in abdication", "C:\\Develop\\MB3\\Source\\Bannerlord\\TaleWorlds.CampaignSystem\\KingdomManager.cs", nameof (AbdicateTheThrone), 224);
        }
        if (kingdom.IsEliminated)
          return;
        DestroyKingdomAction.Apply(kingdom);
      }
    }

    public void RaidCompleted(BattleSideEnum winnerSide, RaidEventComponent raidEvent)
    {
      MapEvent mapEvent = raidEvent.MapEvent;
      switch (winnerSide)
      {
        case BattleSideEnum.Defender:
          foreach (PartyBase involvedParty in mapEvent.InvolvedParties)
          {
            if (involvedParty.MobileParty != null && !involvedParty.MobileParty.IsMilitia && involvedParty.MobileParty.DefaultBehavior == AiBehavior.DefendSettlement && (involvedParty.MobileParty.Army == null || involvedParty.MobileParty.Army.LeaderParty == involvedParty.MobileParty))
              involvedParty.MobileParty.Ai.SetMoveModeHold();
          }
          ChangeVillageStateAction.ApplyBySettingToNormal(mapEvent.MapEventSettlement);
          break;
        case BattleSideEnum.Attacker:
          using (IEnumerator<PartyBase> enumerator = mapEvent.InvolvedParties.GetEnumerator())
          {
            while (enumerator.MoveNext())
            {
              PartyBase current = enumerator.Current;
              if (current.MobileParty != null && current.MobileParty.DefaultBehavior == AiBehavior.RaidSettlement && (current.MobileParty.Army == null || current.MobileParty.Army.LeaderParty == current.MobileParty))
                current.MobileParty.Ai.SetMoveModeHold();
            }
            break;
          }
      }
    }

    public void SiegeCompleted(
      Settlement settlement,
      MobileParty capturerParty,
      bool isWin,
      MapEvent.BattleTypes battleType)
    {
      if (((battleType == MapEvent.BattleTypes.SallyOut ? 1 : (battleType == MapEvent.BattleTypes.Siege ? 1 : 0)) & (isWin ? 1 : 0)) == 0)
        return;
      Hero newOwner = capturerParty.MapFaction is Kingdom mapFaction ? mapFaction.Leader : capturerParty.MapFaction.Leader;
      if (capturerParty.LeaderHero != null)
        GainKingdomInfluenceAction.ApplyForCapturingEnemySettlement(capturerParty, (float) Campaign.Current.Models.DiplomacyModel.GetInfluenceAwardForSettlementCapturer(settlement));
      List<MobileParty> source = new List<MobileParty>();
      foreach (PartyBase partyBase in settlement.SiegeEvent.BesiegerCamp.GetInvolvedPartiesForEventType(MapEvent.BattleTypes.Siege))
        source.Add(partyBase.MobileParty);
      settlement.SiegeEvent.BesiegerCamp.RemoveAllSiegeParties();
      settlement.Party.MemberRoster.Clear();
      ChangeOwnerOfSettlementAction.ApplyBySiege(newOwner, capturerParty.Party.Owner, settlement);
      foreach (MobileParty mobileParty in source)
      {
        EnterSettlementAction.ApplyForParty(mobileParty, settlement);
        if ((mobileParty.Army == null || mobileParty.Army.LeaderParty == mobileParty) && mobileParty != MobileParty.MainParty)
          mobileParty.Ai.DisableForHours(10);
      }
      if (!source.ContainsQ<MobileParty>(MobileParty.MainParty))
        return;
      Debug.Print(capturerParty.StringId + ": " + (object) capturerParty.Name + " has captured " + (object) settlement + " successfully.\n", color: Debug.DebugColor.Green, debugFilter: 64UL);
    }

    private static void UpdateLordPartyVariablesRelatedToSettlements()
    {
      TWParallel.For(0, Settlement.All.Count, (TWParallel.ParallelForAuxPredicate) ((startInclusive, endExclusive) =>
      {
        for (int index = startInclusive; index < endExclusive; ++index)
          Settlement.All[index].NumberOfLordPartiesTargeting = 0;
      }));
      foreach (MobileParty allLordParty in (List<MobileParty>) MobileParty.AllLordParties)
      {
        if (allLordParty.Army == null || allLordParty.Army.LeaderParty == allLordParty)
        {
          if (allLordParty.TargetSettlement != null && allLordParty.CurrentSettlement != allLordParty.TargetSettlement)
          {
            allLordParty.TargetSettlement.NumberOfLordPartiesTargeting += allLordParty.Army == null ? 1 : 1 + allLordParty.Army.LeaderParty.AttachedParties.Count;
          }
          else
          {
            Settlement visitedSettlement = allLordParty.LastVisitedSettlement;
            if ((visitedSettlement != null ? (visitedSettlement.IsVillage ? 1 : 0) : 0) != 0 && (double) allLordParty.LastVisitedSettlement.Position2D.DistanceSquared(allLordParty.Position2D) < 2.0)
              allLordParty.LastVisitedSettlement.NumberOfLordPartiesTargeting += allLordParty.Army == null ? 1 : 1 + allLordParty.Army.LeaderParty.AttachedParties.Count;
          }
        }
      }
    }

    public void RelinquishSettlementOwnership(Settlement settlement)
    {
      SettlementClaimantDecision claimantDecision = new SettlementClaimantDecision(settlement.OwnerClan, settlement, (Hero) null, settlement.OwnerClan);
      settlement.OwnerClan.Kingdom.AddDecision((KingdomDecision) claimantDecision, true);
    }

    public void GiftSettlementOwnership(Settlement settlement, Clan receiverClan)
    {
      int relationChange = settlement.IsTown ? Campaign.Current.Models.DiplomacyModel.GiftingTownRelationshipBonus : Campaign.Current.Models.DiplomacyModel.GiftingCastleRelationshipBonus;
      ChangeRelationAction.ApplyRelationChangeBetweenHeroes(settlement.OwnerClan.Leader, receiverClan.Leader, relationChange);
      ChangeOwnerOfSettlementAction.ApplyByGift(settlement, receiverClan.Leader);
    }

    public IEnumerable<Clan> GetEligibleClansForSettlementOwnershipGift(Settlement settlement)
    {
      Kingdom kingdom = settlement.OwnerClan.Kingdom;
      foreach (Clan clan in (List<Clan>) kingdom.Clans)
      {
        if (clan != kingdom.RulingClan)
          yield return clan;
      }
    }

    private static void QuarterHourlyTick(MBCampaignEvent campaignevent, object[] delegateparams)
    {
      KingdomManager.UpdateLordPartyVariablesRelatedToSettlements();
    }

    public int GetMercenaryWageAmount(Hero hero)
    {
      return (int) hero.Clan.Influence * hero.Clan.MercenaryAwardMultiplier;
    }
  }
}
